package org.baicaixiaozhan.tenet.autoconfigure;

import lombok.AllArgsConstructor;
import org.baicaixiaozhan.tenet.context.spring.SpringContextHandler;
import org.baicaixiaozhan.tenet.nosql.redis.RedisUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * DESC: tenet-util 自动装配配置
 *
 * @author baicaixiaozhan
 * @since 1.0.0
 */
@AllArgsConstructor
@Configuration
public class TenetAutoConfiguration {

    private static final long TTL_OF_MINUTES = 30;

    private final ApplicationContext applicationContext;

    @Bean
    @ConditionalOnMissingBean
    public SpringContextHandler springContextHandler() {
        SpringContextHandler springContextHandler = new SpringContextHandler();
        springContextHandler.setApplicationContext(applicationContext);
        return springContextHandler;
    }

    @Bean
    @ConditionalOnMissingBean(name = {"redisConnectionFactory"})
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory();
    }

    @Bean
    @ConditionalOnMissingBean(name = {"redisTemplate"})
    public RedisTemplate<String, Object> redisTemplate() {
        // 配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        RedisSerializer<?> stringSerializer = new StringRedisSerializer();
        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
        // key序列化
        redisTemplate.setKeySerializer(stringSerializer);
        // value序列化
        redisTemplate.setValueSerializer(serializer);
        // Hash key序列化
        redisTemplate.setHashKeySerializer(stringSerializer);
        // Hash value序列化
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

    /**
     * 防止反序列化失败
     */
    @Bean
    @ConditionalOnMissingBean(name = {"redisCacheManager"})
    public RedisCacheManager redisCacheManager(){
        RedisSerializationContext.SerializationPair<Object> objectSerializationPair = RedisSerializationContext.SerializationPair
                .fromSerializer(new GenericJackson2JsonRedisSerializer());
        return RedisCacheManager.builder(redisConnectionFactory())
                .cacheDefaults(
                        RedisCacheConfiguration.defaultCacheConfig(Thread.currentThread().getContextClassLoader())
                                .serializeValuesWith(objectSerializationPair)
                )
                .build();
    }

    @Bean
    @ConditionalOnMissingBean(name = "redisUtils")
    public RedisUtils redisUtils() {
        return new RedisUtils(TTL_OF_MINUTES, redisTemplate());
    }

}
